//***************************************************************************
//   Copyright(c)2020, Xidian University D405.
//   All rights reserved
//
//   IP Name         :   Null
//   File name       :   np_dma_tx_desc.v
//   Module name     :   np_dma_tx_desc
//   Author          :   Wang Zekun
//   Date            :   2022/04/25
//   Version         :   v1.4 
//   Verison History :   v1.0/v1.1/v1.2/v1.3/v1.4
//   Edited by       :   Wang Zekun
//   Modification history : v1.0 Initial revision
//                          v1.1 change tx port sel at read data done
//                          v1.2 according to 0414 axi master rtl,need to change port sel
//                          v1.3 desc address 40bit,data address 40bit, data address align 64B--0x40--0b0100_0000
//                          v1.4 desc new function IOC
// ----------------------------------------------------------------------------
// Version 1.4       Date(2022/04/25)
// Abstract : tx descriptor parse and construct
//-----------------------------------------------------------------------------
// Programmer's model
//                    tdesc_i_0--------packet address[31:0]
//                    tdesc_i_1--------reserved[31:0]
//                    tdesc_i_2--------reserved[31:0]
//                    tdesc_i_3--------{own,ioc,port,reserved[28:20],length[19:0]}
//-----------------------------------------------------------------------------
//interface list :
//                
`timescale 1ps/1ps
module np_dma_tx_desc #(
    parameter AXI_ADDR_WIDTH = 40,
    parameter AXI_LIB_WIDTH = 20
  )(
  input  wire                               clk_i,
  input  wire                               resetn_i,
  
  input  wire                               read_already_done_i,

  input  wire                               tx_start_en_i,    // from ahb decode,only once
  input  wire                               tx_start_circle_i,

  output wire                               tx_descfifo_read_en_o,
  input  wire                               tx_desc_fifo_rd_empty_i,
  input  wire                               tx_desc_read_valid_i,
  input  wire [127:0]                       tx_desc_i,

  input  wire                               tx_fifo_full_i,
  input  wire                               tx_patcket_length_valid_i,
  //input  wire [AXI_LIB_WIDTH-1 :0]         tx_patcket_length_i,
  //input  wire                               tx_port_status_i,

  output wire                               tx_desc_constr_valid_o,
  output wire [127:0]                       tx_desc_o,

  output wire                               tx_desc_parse_valid_o,
  output wire                               tx_port_status_o,
  output wire [AXI_ADDR_WIDTH-1:0]          tx_packet_address_o,
  output wire [AXI_LIB_WIDTH-1 :0]          tx_patcket_length_o,
  output wire                               tx_desc_ioc_o,
  output wire                               tx_desc_own_o

);

  reg  [127:0]                        tx_desc_i_r;
  wire [31:0]                         tdesc_i_0;
  wire [31:0]                         tdesc_i_1;
  wire [31:0]                         tdesc_i_2;
  wire [31:0]                         tdesc_i_3;
  wire                                tx_port_status;
  reg                                 tx_port_status_r;

  reg  [31:0]                         tdesc_o_0;
  reg  [31:0]                         tdesc_o_1;
  reg  [31:0]                         tdesc_o_2;
  reg  [31:0]                         tdesc_o_3;

  reg                                 tx_desc_parse_valid_r;
  reg                                 tx_start_circle_r;
  reg                                 tx_desc_construct;
  reg                                 tx_desc_construct_r;

  reg                                 first_read_desc;
  
  always @(posedge clk_i or negedge resetn_i) begin
    if(~resetn_i) begin
      first_read_desc <= 1'b0;
    end
    else if(tx_desc_construct) begin
      first_read_desc <= 1'b0;
    end
    else if(tx_start_en_i) begin
      first_read_desc <= 1'b1;
    end
    else begin
      first_read_desc <= first_read_desc;
    end
  end
  
  // packet length store

  // packet address caculate

  //***********************
  //********tdesc read enable
  //***********************
    // read desc enable lock
  always @(posedge clk_i or negedge resetn_i) begin
    if(~resetn_i) begin
      tx_start_circle_r <= 1'b0;
    end
    else if(tx_descfifo_read_en_o) begin
      tx_start_circle_r <= 1'b0;
    end
    else if(tx_start_circle_i) begin //tx_desc_construct_r | tx_start_en_i
      tx_start_circle_r <= 1'b1;
    end
    else begin
      tx_start_circle_r <= tx_start_circle_r;
    end
  end
  
  assign tx_descfifo_read_en_o = tx_fifo_full_i | tx_desc_fifo_rd_empty_i ? 1'b0 : tx_start_circle_r;

  //***********************
  //********parse procedure
  //***********************
  always @(posedge clk_i or negedge resetn_i) begin
    if(~resetn_i) begin
      tx_desc_i_r <= {128{1'b0}};
    end
    else if(tx_desc_read_valid_i) begin
      tx_desc_i_r <= tx_desc_i;
    end
    else begin
      tx_desc_i_r <= tx_desc_i_r;
    end
  end

  always @(posedge clk_i or negedge resetn_i) begin
    if(~resetn_i) begin
      tx_desc_parse_valid_r <= 1'b0;
    end
    else begin
      tx_desc_parse_valid_r <= tx_desc_read_valid_i;
    end
  end

  assign tdesc_i_0 = tx_desc_i_r[31:0];
  assign tdesc_i_1 = tx_desc_i_r[63:32];
  assign tdesc_i_2 = tx_desc_i_r[95:64];
  assign tdesc_i_3 = tx_desc_i_r[127:96];

  assign tx_packet_address_o   = {tdesc_i_1[7:0],tdesc_i_0};
  assign tx_patcket_length_o   = tdesc_i_3[19:0];
  assign tx_port_status        = tdesc_i_3[29];
  assign tx_desc_ioc_o         = tdesc_i_3[30];//1'b1;
  assign tx_desc_own_o         = tdesc_i_3[31];

  assign tx_desc_parse_valid_o  = tx_desc_parse_valid_r;// & tx_desc_own_o;

  //***********************
  //********construct procedure
  //***********************
  always @(posedge clk_i or negedge resetn_i) begin
    if(~resetn_i) begin
      tx_desc_construct   <= 1'b0;
      tx_desc_construct_r <= 1'b0;
    end
    else begin
      tx_desc_construct   <= tx_desc_parse_valid_o;
      tx_desc_construct_r <= tx_desc_construct;
    end
  end

    // tdesc1,tdesc0 construct packet address
  always @(posedge clk_i or negedge resetn_i) begin
    if(~resetn_i) begin
      tdesc_o_0      <= {32{1'b0}};
      tdesc_o_1[7:0] <= {8{1'b0}};
    end
    else if(tx_desc_construct) begin
      tdesc_o_0      <= tx_packet_address_o[31:0];
      tdesc_o_1[7:0] <= tx_packet_address_o[AXI_ADDR_WIDTH-1:32];
    end
    else begin
      tdesc_o_0      <= tdesc_o_0;
      tdesc_o_1[7:0] <= tdesc_o_1[7:0];
    end
  end

    // tdesc1/2/3 reserved
  always @(posedge clk_i or negedge resetn_i) begin
    if(~resetn_i) begin
      tdesc_o_1[31:8]  <= {24{1'b0}};
      tdesc_o_2        <= {32{1'b0}};
      tdesc_o_3[28:20] <= {9{1'b0}};
    end
    else if(tx_desc_construct) begin
      tdesc_o_1[31:8]  <= tdesc_i_1[31:8];
      tdesc_o_2        <= tdesc_i_2;
      tdesc_o_3[28:20] <= tdesc_i_3[28:20];
    end
    else begin
      tdesc_o_1[31:8]  <= tdesc_o_1[31:8];
      tdesc_o_2        <= tdesc_o_2;
      tdesc_o_3[28:20] <= tdesc_o_3[28:20];
    end
  end

    // tdesc3 construct
  always @(posedge clk_i or negedge resetn_i) begin
    if(~resetn_i) begin
      tdesc_o_3[31:29] <= 3'b00;
      tdesc_o_3[19:0]  <= {20{1'b0}};
    end
    else if(tx_desc_construct) begin
      tdesc_o_3[31:29] <= {1'b0,tx_desc_ioc_o,tx_port_status_o};
      tdesc_o_3[19:0]  <= {{20-AXI_LIB_WIDTH{1'b0}},tx_patcket_length_o};
    end
    else begin
      tdesc_o_3[31:29] <= tdesc_o_3[31:29];
      tdesc_o_3[19:0]  <= tdesc_o_3[19:0];
    end
  end

  always @(posedge clk_i or negedge resetn_i) begin
    if(~resetn_i) begin
      tx_port_status_r <= 1'b0;
    end
    else if(read_already_done_i) begin
      tx_port_status_r <= tx_port_status;
    end
    else begin
      tx_port_status_r <= tx_port_status_r;
    end
  end

  assign tx_port_status_o = tx_port_status;//tx_port_status_r;
  assign tx_desc_o = tx_desc_constr_valid_o ? {tdesc_o_3,tdesc_o_2,tdesc_o_1,tdesc_o_0} : {128{1'b0}};
  assign tx_desc_constr_valid_o = tx_desc_construct_r;

endmodule